package generic;

import org.junit.Test;

import java.util.ArrayList;

/**编译时擦除泛型
test和test1 都验证泛型在编译期间被擦除了
 */
public class ChaChu {

        @Test
        public void test() {

            ArrayList<String> list1 = new ArrayList<String>();
            list1.add("abc");

            ArrayList<Integer> list2 = new ArrayList<Integer>();
            list2.add(123);

            System.out.println(list1.getClass() == list2.getClass()); //true
            //说明泛型类型String和Integer都被擦除掉了，只剩下原始类型。
        }

        @Test
    public void test2() throws Exception {
            ArrayList<Integer> list = new ArrayList<Integer>();

            list.add(1);
            //这样调用 add 方法只能存储整形，因为泛型类型的实例为 Integer

            list.getClass().getMethod("add", Object.class).invoke(list, "asd");
            //当我们利用反射调用add()方法的时候，却可以存储字符串，这说明了Integer泛型实例在编译之后被擦除掉了，只保留了原始类型。

            for (int i = 0; i < list.size(); i++) {
                System.out.println(list.get(i));
            }
        }

        @Test
    public void test3(){
            ArrayList<String> list1 = new ArrayList();
            list1.add("1"); //编译通过
//            list1.add(1); //编译错误
            String str1 = list1.get(0); //返回类型就是String

            ArrayList list2 = new ArrayList<String>();
            list2.add("1"); //编译通过
            list2.add(1); //编译通过
            Object o = list2.get(0);//返回类型就是Object

            new ArrayList<String>().add("11"); //编译通过
//            new ArrayList<String>().add(22); //编译错误

            String str2 = new ArrayList<String>().get(0); //返回类型就是String
        }

    }



/**
 * 在调用泛型方法时，可以指定泛型，也可以不指定泛型。

 在不指定泛型的情况下，泛型变量的类型为该方法中的几种类型的同一父类的最小级，直到Object
 在指定泛型的情况下，该方法的几种类型必须是该泛型的实例的类型或者其子类
 */
class Test1 {
    public static void main(String[] args) {

        /**不指定泛型的时候*/
        int i = Test1.add(1, 2); //这两个参数都是Integer，所以T为Integer类型
        Number f = Test1.add(1, 1.2); //这两个参数一个是Integer，以风格是Float，所以取同一父类的最小级，为Number
        Object o = Test1.add(1, "asd"); //这两个参数一个是Integer，以风格是Float，所以取同一父类的最小级，为Object

        /**指定泛型的时候*/
        int a = Test1.<Integer>add(1, 2); //指定了Integer，所以只能为Integer类型或者其子类
//        int b = Test1.<Integer>add(1, 2.2); //编译错误，指定了Integer，不能为Float
        Number c = Test1.<Number>add(1, 2.2); //指定为Number，所以可以为Integer和Float
    }

    //这是一个简单的泛型方法
    public static <T> T add(T x,T y){
        return y;
    }
}